package cn.sinjet.model.mcuupgrade;

import java.io.File;
import java.io.FileInputStream;

import android.os.Environment;
import android.util.Log;

public class MCUFileRead {
	public String magicStringNeed = null;
	public String magicStringFind = null;
	public int version = 0;

	public byte[] binData = null;
	public int binCRC;

	public boolean haveBinData() {
		if (binData != null) {
			return true;
		}
		return false;
	}

	public boolean isValidFile(String magicString) {
		if (binData != null && version > 0 && magicStringFind != null && magicStringFind.equals(magicString)) {
			return true;
		}
		return false;
	}
	
	public int frameCountBinData(int frameSize) {
		if (binData == null || binData.length == 0) {
			return 0;
		}
		return (binData.length+frameSize-1)/frameSize;
	}
	
	//////////////////////////////////////////////////////////////////decode hex start
	boolean flashStartAddrHaveRead;
	long flashStartAddr;
	long flashNowAddr;
	int flashAddrH16;
	int flashAddrL16;
	
	private int dealHexLine(byte[] hexLineData,byte[] binData,int binOffset) {
		int len = MCUUpgradeCommonFunction.getUnsignedByte(hexLineData[0]);
		int id = MCUUpgradeCommonFunction.getUnsignedByte(hexLineData[3]);
		
		switch (id) {
		case 0x05:
			flashAddrH16 = (MCUUpgradeCommonFunction.getUnsignedByte(hexLineData[4]) << 8) + MCUUpgradeCommonFunction.getUnsignedByte(hexLineData[5]);
			flashAddrL16 = (MCUUpgradeCommonFunction.getUnsignedByte(hexLineData[6]) << 8) + MCUUpgradeCommonFunction.getUnsignedByte(hexLineData[7]);
		case 0x04:
			flashAddrH16 = (MCUUpgradeCommonFunction.getUnsignedByte(hexLineData[4]) << 8) + MCUUpgradeCommonFunction.getUnsignedByte(hexLineData[5]);
			break;
		case 0x00:
			flashAddrL16 = (MCUUpgradeCommonFunction.getUnsignedByte(hexLineData[1]) << 8) + MCUUpgradeCommonFunction.getUnsignedByte(hexLineData[2]);
			long flashWriteAddr = (flashAddrH16 << 16) + flashAddrL16;
			if (flashStartAddrHaveRead == false) {
				flashStartAddrHaveRead = true;
				flashStartAddr = flashWriteAddr;
				flashNowAddr = flashStartAddr;
			}
			if (flashNowAddr != flashWriteAddr)
			{
				Log.d("mcu_upgrade","dealHexLine addr jump!");
				return -1;
			}
			if (len > 0x10)
			{
				Log.d("mcu_upgrade","dealHexLine len too long!");
				return -1;
			}
			System.arraycopy(hexLineData, 4, binData, binOffset, len);
			binOffset += len;
			flashNowAddr += len;
			break;
		default:
			break;
		}
		
		return binOffset;
	}

	//////////////////////////////////////////////////////////////////MCU File Version Start
	private void findMagicString(byte[] binFile) {
		Log.d("mcu_upgrade","findMagicString ");
		
		String strMagicModule = "#SW_MODULE#";
		byte[] sMagicModule = strMagicModule.getBytes();
		
		String strMagicDate = "#SW_DATE#";
		byte[] sMagicDate = strMagicDate.getBytes();
		
		for (int i = 4;i < binFile.length;i++) {
			int j;
			
			//magic module
			for (j = 0;j < sMagicModule.length;j++) {
				if (sMagicModule[j] != binFile[i+j]) {
					break;
				}
			}
			if (j == sMagicModule.length) {//compare ok
				byte[] byteArray = new byte[8];
				System.arraycopy(binFile, i+j, byteArray, 0, byteArray.length);
				magicStringFind = new String(byteArray);
			}
			
			//magic date
			for (j = 0;j < sMagicDate.length;j++) {
				if (sMagicDate[j] != binFile[i+j]) {
					break;
				}
			}
			if (j == sMagicDate.length) {//compare ok
				byte[] byteArray = new byte[8];
				System.arraycopy(binFile, i+j, byteArray, 0, byteArray.length);
				version = MCUUpgradeCommonFunction.transVersionToInt(byteArray);
			}
		}
	}
	//////////////////////////////////////////////////////////////////MCU File Version Finish
	
	private boolean checkHexLineCRC(byte[] hexLine,int hexLineLength) {
		int crc = 0;
		int crcRec = MCUUpgradeCommonFunction.getUnsignedByte(hexLine[hexLineLength-1]);
		for (int i = 0;i < hexLineLength-1;i++) {
			crc += MCUUpgradeCommonFunction.getUnsignedByte(hexLine[i]);
		}
		crc = crc & 0xFF;
		crc = 0x100 - crc;
		crc = crc & 0xFF;
		if (crc == crcRec) {
			return true;
		}
		else {
			Log.d("mcu_upgrade","checkHexLineCRC error!");
			return false;
		}
	}
	
	private void decodeHexToBin(byte[] hexData,boolean needFindMagicString) {
		Log.d("mcu_upgrade","decodeHexToBin ");
		int hexLineOffset = 0;
		byte[] hexLineData = new byte[64];
		byte charHigh = 0;
		
		byte[] binDataTemp = new byte[hexData.length];
		int binOffset = 0;
		
		flashStartAddrHaveRead = false;
		flashStartAddr = 0;
		
		for (byte byteChar : hexData) {
			int uByteChar = MCUUpgradeCommonFunction.getUnsignedByte(byteChar);
			if (uByteChar == ':' || uByteChar == 0x0D || uByteChar == 0x0A) {
				if (hexLineOffset > 0) {
					if (!checkHexLineCRC(hexLineData,(hexLineOffset+1)/2)) {
						return;
					}
					binOffset = dealHexLine(hexLineData,binDataTemp,binOffset);
					if (-1 == binOffset)
					{
						return;
					}
				}
				hexLineOffset = 0;
			}
			else {
				if (hexLineOffset % 2 == 0) {
					charHigh = byteChar;
				}
				else {
					hexLineData[hexLineOffset/2] = (byte)((Character.digit(charHigh, 16) << 4) + Character.digit(byteChar, 16));
				}
				hexLineOffset++;
			}
		}
		
		binData = new byte[4+binOffset];
		binData[0] = (byte)(flashStartAddr&0x0FF);
		binData[1] = (byte)((flashStartAddr>>8)&0x0FF);
		binData[2] = (byte)((flashStartAddr>>16)&0x0FF);
		binData[3] = (byte)((flashStartAddr>>24)&0x0FF);
		System.arraycopy(binDataTemp, 0, binData, 4, binOffset);
		
		int binCRCCalc = 0;
		for (int i = 0;i < binData.length;i++) {
			binCRCCalc += MCUUpgradeCommonFunction.getUnsignedByte(binData[i]);
		}
		binCRC = binCRCCalc;
		
		if (needFindMagicString)
		{
			findMagicString(binData);
		}
	}
	//////////////////////////////////////////////////////////////////decode hex finish

	public void readHexFile(String fileName,String magicString,boolean needFindMagicString) {
		Log.d("mcu_upgrade","readHexFile " + magicString + fileName);
		magicStringNeed = magicString;
		try {
			File file = new File(Environment.getExternalStorageDirectory(),fileName);
			FileInputStream fin = new FileInputStream(file);
			
			int length = fin.available();

			byte[] hexData = null;
			
			if (length > 0)
			{
				hexData = new byte[length];
				fin.read(hexData);					
			}
			
			fin.close();
			
			decodeHexToBin(hexData,needFindMagicString);
		}
		catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}
